#include <thread>
#include <list>
#include "net_tool.h"
#include "Node.h"
#include "string.h"
#include <iostream>
#include <unistd.h>
LocalMaster localMaster;
void LocalMaster::sendMsg(const char * msg) {
    DataFrame df;
    size_t len = strlen(msg) + 1;
    for (auto i = this->slavesMap.begin(); i != this->slavesMap.end(); i++) {
        df.sendFrame(i->first->si.socket_fd, PC::CtrlFrameFlag::sendmsg, len);
        send(i->first->si.socket_fd, msg, len, MSG_WAITALL);
    }
    
}

LocalMaster::LocalMaster() {
    std::thread th(&LocalMaster::sendDoki, this);
    th.detach();
}

void LocalMaster::sendDoki() {
    std::list<Slave *> removelist;
    while (1) {
        removelist.clear();
        this->mapMutex.lock();
        auto end = this->slavesMap.end();
        for (auto i = this->slavesMap.begin(); i != end; i++) {
            if(i->first->doki++ > 2) {
                removelist.push_back(i->first);
            } else {
                std::thread th(&Slave::sendDoki, i->first);
                th.detach();
            }
        }
        this->mapMutex.unlock();
        for (auto i = removelist.begin(); i!=removelist.end(); i++){
            this->removeSlave(*i);
        }
        sleep(3);
    }
    
}

void LocalMaster::recvDoki(Slave * slave) {
    DataFrame df;
    try {
        while (df.readFrame(slave->si.socket_fd)) {
            slave->doki = 0;
            // std::cout << "Recive doki from slave" << std::endl;
        }
    } catch (...) {
        this->removeSlave(slave);
    }
}

void LocalMaster::addSlave(Slave * slave) {
    this->mapMutex.lock();
    this->slavesMap[slave] = slave;
    std::thread th1(&LocalMaster::recvDoki, this, slave);
    this->mapMutex.unlock();
    th1.detach();
}

void LocalMaster::removeSlave(Slave * slave) {
    this->mapMutex.lock();
    if(this->slavesMap.count(slave)) {
        this->slavesMap.erase(slave);
        delete(slave);
    }
    this->mapMutex.unlock();
}

void LocalMaster::printSlaves() {
    char ip[16];
    this->mapMutex.lock();
    for (auto i = this->slavesMap.begin(); i != this->slavesMap.end(); i++) {
        i->first->si.getip(ip);
        std::cout << "IP:" << ip << " port: " << ntohs(i->first->si.addr.sin_port) << std::endl;
    }
    this->mapMutex.unlock();
}